#pragma once

#ifndef __CR_CORE_FILE_SYSTEM_PATH_TRAITS_H__
#define __CR_CORE_FILE_SYSTEM_PATH_TRAITS_H__

NS_CR_BEGIN

namespace filesystem
{
	namespace path_traits
	{
		typedef _STD codecvt<wchar_t, char, _STD mbstate_t> codecvt_type;

		template <class T>
		struct is_pathable
		{
			static const bool value = false;
		};

		template<> struct is_pathable<char*>					{ static const bool value = true; };
		template<> struct is_pathable<const char*>				{ static const bool value = true; };
		template<> struct is_pathable<wchar_t*>					{ static const bool value = true; };
		template<> struct is_pathable<const wchar_t*>			{ static const bool value = true; };
		template<> struct is_pathable<std::string>				{ static const bool value = true; };
		template<> struct is_pathable<std::wstring>				{ static const bool value = true; };
		template<> struct is_pathable<std::vector<char> >		{ static const bool value = true; };
		template<> struct is_pathable<std::vector<wchar_t> >	{ static const bool value = true; };
		template<> struct is_pathable<std::list<char> >			{ static const bool value = true; };
		template<> struct is_pathable<std::list<wchar_t> >		{ static const bool value = true; };

		template <class Container> 
		INLINE typename disable_if<_STD is_array<Container>, bool>::type
			empty(const Container& c)
		{
			return c.begin() == c.end();
		}

		template <class T> 
		INLINE bool empty(T* const& c_str)
		{
			CR_ASSERT(c_str);
			return !*c_str;
		}

		template <typename T, size_t N> 
		INLINE bool empty(T(&x)[N])
		{
			return !x[0];
		}

		void convert(const char* from, const char* from_end, std::wstring & to, const codecvt_type& cvt);
		void convert(const wchar_t* from, const wchar_t* from_end, std::string & to, const codecvt_type& cvt);

		INLINE void convert(const char* from, std::wstring & to, const codecvt_type& cvt)
		{
			CR_ASSERT(from);
			convert(from, 0, to, cvt);
		}

		 INLINE void convert(const wchar_t* from, std::string & to, const codecvt_type& cvt)
		{
			 CR_ASSERT(from);
			convert(from, 0, to, cvt);
		}

		 INLINE void convert(const char* from, const char* from_end, std::wstring & to);
		 
		 INLINE void convert(const wchar_t* from, const wchar_t* from_end, std::string & to);

		 INLINE	void convert(const char* from, std::wstring & to);

		 INLINE void convert(const wchar_t* from, std::string & to);

		 INLINE void convert(const char* from, const char* from_end, std::string & to, const codecvt_type&)
		 {
			 CR_ASSERT(from);
			 CR_ASSERT(from_end);
			 to.append(from, from_end);
		 }

		 INLINE void convert(const char* from, std::string & to, const codecvt_type&)
		 {
			 CR_ASSERT(from);
			 to += from;
		 }

		 // wchar_t with codecvt

		 INLINE void convert(const wchar_t* from, const wchar_t* from_end, std::wstring & to, const codecvt_type&)
		 {
			 CR_ASSERT(from);
			 CR_ASSERT(from_end);
			 to.append(from, from_end);
		 }

		 INLINE void convert(const wchar_t* from,
				 std::wstring & to,
				 const codecvt_type&)
		 {
			 CR_ASSERT(from);
			 to += from;
		 }

		 // char without codecvt

		 INLINE void convert(const char* from, const char* from_end, std::string & to)
		 {
			 CR_ASSERT(from);
			 CR_ASSERT(from_end);
			 to.append(from, from_end);
		 }

		 INLINE void convert(const char* from, std::string & to)
		 {
			 CR_ASSERT(from);
			 to += from;
		 }

		 // wchar_t without codecvt

		 INLINE void convert(const wchar_t* from, const wchar_t* from_end, std::wstring & to)
		 {
			 CR_ASSERT(from);
			 CR_ASSERT(from_end);
			 to.append(from, from_end);
		 }

		 INLINE void convert(const wchar_t* from, std::wstring & to)
		 {
			 CR_ASSERT(from);
			 to += from;
		 }

		 //  Source dispatch  -----------------------------------------------------------------//

		 template <class U>
		 INLINE	void dispatch(const std::string& c, U& to, const codecvt_type& cvt)
		 {
			 if (c.size())
				 convert(&*c.begin(), &*c.begin() + c.size(), to, cvt);
		 }
		 template <class U>
		 INLINE void dispatch(const std::wstring& c, U& to, const codecvt_type& cvt)
		 {
			 if (c.size())
				 convert(&*c.begin(), &*c.begin() + c.size(), to, cvt);
		 }
		 template <class U>
		 INLINE void dispatch(const std::vector<char>& c, U& to, const codecvt_type& cvt)
		 {
			 if (c.size())
				 convert(&*c.begin(), &*c.begin() + c.size(), to, cvt);
		 }
		 template <class U>
		 INLINE void dispatch(const std::vector<wchar_t>& c, U& to, const codecvt_type& cvt)
		 {
			 if (c.size())
				 convert(&*c.begin(), &*c.begin() + c.size(), to, cvt);
		 }

		 template <class U>
		 INLINE void dispatch(const std::string& c, U& to)
		 {
			 if (c.size())
				 convert(&*c.begin(), &*c.begin() + c.size(), to);
		 }
		 template <class U>
		 INLINE void dispatch(const std::wstring& c, U& to)
		 {
			 if (c.size())
				 convert(&*c.begin(), &*c.begin() + c.size(), to);
		 }
		 template <class U>
		 INLINE void dispatch(const std::vector<char>& c, U& to)
		 {
			 if (c.size())
				 convert(&*c.begin(), &*c.begin() + c.size(), to);
		 }
		 template <class U> 
		 INLINE void dispatch(const std::vector<wchar_t>& c, U& to)
		 {
			 if (c.size())
				 convert(&*c.begin(), &*c.begin() + c.size(), to);
		 }

		 template <class Container, class U>
		 INLINE typename disable_if<_STD is_array<Container>, void>::type
			 dispatch(const Container& c, U& to, const codecvt_type& cvt)
		 {
			 if (c.size())
			 {
				 std::basic_string<typename Container::value_type> s(c.begin(), c.end());
				 convert(s.c_str(), s.c_str() + s.size(), to, cvt);
			 }
		 }

		 template <class T, class U>
		 INLINE void dispatch(T* const& c_str, U& to, const codecvt_type& cvt)
		 {
			 CR_ASSERT(c_str);
			 convert(c_str, to, cvt);
		 }

// #if _WIN32
// 		 void dispatch(const directory_entry & de, std::wstring & to, const codecvt_type&);
// #else
// 		 void dispatch(const directory_entry & de, std::string & to, const codecvt_type&);
// #endif
		 template <class Container, class U> 
		 INLINE typename disable_if<_STD is_array<Container>, void>::type
			 dispatch(const Container & c, U& to)
		 {
			 if (c.size())
			 {
				 std::basic_string<typename Container::value_type> s(c.begin(), c.end());
				 convert(s.c_str(), s.c_str() + s.size(), to);
			 }
		 }

		 template <class T, class U>
		 INLINE void dispatch(T * const & c_str, U& to)
		 {
			 CR_ASSERT(c_str);
			 convert(c_str, to);
		 }
// #if _WIN32
// 		 void dispatch(const directory_entry & de, std::wstring & to);
// #else
// 		 void dispatch(const directory_entry & de, std::string & to);
// #endif
	}
}
NS_CR_END

#endif // !__CR_CORE_FILE_SYSTEM_PATH_TRAITS_H__
